package com.beyondsoft.dtc.mobile.automation.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;

import com.beyondsoft.dtc.mobile.automation.base.GlobalConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Created by Robin on 3/11/2016.
 */
public class ShellUtil {
	private final static Logger logger = LoggerFactory
			.getLogger(ShellUtil.class);

	// public static final String COMMAND_SU = "su";
	// public static final String COMMAND_SH = "sh";
	// public static final String COMMAND_EXIT = "exit\n";
	// public static final String COMMAND_LINE_END = "\n";

	// default time out, in millseconds
	public static final int DEFAULT_TIMEOUT = 10 * 1000;
	public static final int DEFAULT_INTERVAL = 1000;

	private ShellUtil() {
		throw new AssertionError();
	}

	public static void execCommandNoWait(String[] commands) {
		if (commands == null || commands.length == 0) {
			logger.error("Error: commands list is empty!");
		}

		Process process = null;
		try {
			process = Runtime.getRuntime().exec(commands);

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (process != null) {
				process.destroy();
			}
		}
	}

	/**
	 * 默认 代打印效果
	 * 
	 * @param commands
	 * @return
	 */
	public static CommandResult execCommand(String[] commands) {
		return execCommandWithTimeout(commands, true,1000* 60 *5);
	}

	/**
	 * 不打印log
	 * 
	 * @param commands
	 * @return
	 */
	public static CommandResult execCommandNoLog(String[] commands) {
		return execCommand(commands, false);
	}

	public static CommandResult execCommand(String[] commands, Boolean showLog) {
//		logger.error(Arrays.toString(commands));
		int result = -1;
		if (commands == null || commands.length == 0) {
			logger.error("Error: commands list is empty!");
			return new CommandResult(commands, result,
					"Error: commands list is empty!");
		}

		Process process = null;
		StreamGrabber errorGrabber;
		StreamGrabber outputGrabber;

		StringBuilder successMsg = new StringBuilder();
		StringBuilder errorMsg = new StringBuilder();

		try {
			process = Runtime.getRuntime().exec(commands);

			// get commands results
			errorGrabber = new StreamGrabber(process.getErrorStream(), "ERROR",
					errorMsg);
			errorGrabber.start();

			outputGrabber = new StreamGrabber(process.getInputStream(),
					"OUTPUT", successMsg);
			outputGrabber.start();

			result = process.waitFor();
			outputGrabber.join();
			errorGrabber.join();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (process != null) {
				process.destroy();
			}
		}

		if (successMsg.toString().contains("starting it now on port")) {
			return execCommand(commands);
		}

		if (errorMsg.length() > 0) {
			successMsg.append(errorMsg);
		}
		CommandResult commandResult = new CommandResult(commands, result,
				successMsg.toString().trim());
		if (showLog) {
			logger.debug("{}", commandResult);
		}
		return commandResult;
	}

	/**
	 * shell超时处理（慎用：过了超时时间，就会返回（monkey不能用，install可以设定最大时间3-4分钟超时操作））
	 * 
	 * @param commands
	 * @param showLog
	 * @param millisecond
	 *            :设置超时时间
	 * @return
	 */
	public static CommandResult execCommandWithTimeout(String[] commands,
			Boolean showLog, int millisecond) {
		logger.error(Arrays.toString(commands));
		int result = -1;
		if (commands == null || commands.length == 0) {
			logger.error("Error: commands list is empty!");
			return new CommandResult(commands, result,
					"Error: commands list is empty!");
		}

		Process process = null;
		StreamGrabber errorGrabber;
		StreamGrabber outputGrabber;

		StringBuilder successMsg = new StringBuilder();
		StringBuilder errorMsg = new StringBuilder();

		try {
			process = Runtime.getRuntime().exec(commands);

			// get commands results
			errorGrabber = new StreamGrabber(process.getErrorStream(), "ERROR",
					errorMsg);
			errorGrabber.start();

			outputGrabber = new StreamGrabber(process.getInputStream(),
					"OUTPUT", successMsg);
			outputGrabber.start();

			// timeout control :参考：http://lee79.iteye.com/blog/418549
			long start = System.currentTimeMillis();
			boolean processFinished = false;
			while (System.currentTimeMillis() - start < millisecond
					&& !processFinished) {
				processFinished = true;
				try {
					process.exitValue();
				} catch (IllegalThreadStateException e) {
					// process hasn't finished yet
					processFinished = false;

					try {
						Thread.sleep(DEFAULT_INTERVAL);
					} catch (InterruptedException e1) {
						logger.error(
								"Process, failed [" + e.getMessage() + "]");
					}
				}
			}

			if (!processFinished) {
				CommandResult commandResult = new CommandResult(commands,
						result, "Command process timeout");
				logger.debug("{}", commandResult);
				return commandResult;
			}
			result = process.waitFor();
			outputGrabber.join();
			errorGrabber.join();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (process != null) {
				process.destroy();
			}
		}

		if (errorMsg.length() > 0) {
			successMsg.append(errorMsg);
		}
		if (successMsg.toString().contains("starting it now on port")) {
			return execCommand(commands);
		}
		CommandResult commandResult = new CommandResult(commands, result,
				successMsg.toString().trim());
		if (showLog) {
			logger.debug("{}", commandResult);
		}
		return commandResult;
	}

	public static class CommandResult {

		private int resultCode = -1;
		private String[] commands;
		private String resultMsg = "";

		public CommandResult(String[] commands, int errorCode, String resultMsg) {
			this.commands = commands;
			this.resultCode = errorCode;
			this.resultMsg = resultMsg;
		}

		public String[] getCommands() {
			return commands;
		}

		public int getResultCode() {
			return resultCode;
		}

		public String getResultMsg() {
			return resultMsg;
		}

		// 大致的判定，命令是否执行成功
		public boolean isCommandSucceeded() {
			return resultCode == 0;
		}

		// 判定是否命令执行timeout了（此方法和ShellUtil.execCommandWithTimeout一起配套使用的）
		public boolean isCommandTimeOut() {
			return resultCode == -1;
		}

		@Override
		public String toString() {
			return ">> CommandResult{" + "resultCode=" + resultCode
					+ ", commands=" + StringUtil.toString(commands) +
					// ", resultMsg='" + (resultMsg != null &&
					// resultMsg.length() > 520 ? resultMsg.substring(0, 520) :
					// resultMsg) + '\'' +
					", resultMsg=" + resultMsg + '}';
		}
	}

	public static class StreamGrabber extends Thread {
		private InputStream is;
		private String flag;
		private StringBuilder output;

		public StreamGrabber(InputStream is, String flag, StringBuilder output) {
			this.is = is;
			this.flag = flag;
			this.output = output;
		}

		public void run() {
			BufferedReader br = null;
			try {
				br = new BufferedReader(new InputStreamReader(is));
				String line;
				while ((line = br.readLine()) != null) {
					if (output != null && !StringUtil.isEmpty(line)) {
						output.append(line);
						if (!line.endsWith(GlobalConstants.SYMBOL_CRLF)) {
							output.append(GlobalConstants.SYMBOL_CRLF);
						}
					}
				}
			} catch (IOException ioe) {
				ioe.printStackTrace();
			} finally {
				try {
					if (br != null) {
						br.close();
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	/**
	 * 杀掉
	 */
	public static void killContainsSubString(String cmdSub) {
		String[] command = {
				"sh",
				"-c",
				"ps -ef|grep " + cmdSub
						+ " |grep -v grep|cut -c 9-15|xargs kill -9" }; // power
																		// on/off
																		// code
		ShellUtil.execCommand(command);
	}

	/**
	 * 有时候碰见这个错误：“# A fatal error has been detected by the Java Runtime
	 * Environment:”，后续说法是执行“ulimit -c unlimited” 不知道效果如何
	 */
	public static void setJavaEnvCmdExc() {
		String[] command = { "ulimit -c unlimited" }; // power on/off code
		ShellUtil.execCommand(command);
	}

	public static void killAdbServer() {
//		String[] command = { "sh", "-c", "adb kill-server" }; // power on/off
																// code
//		ShellUtil.execCommand(command);
	}

}
